#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Webhook 接收器
用于接收 Gitee 的 Webhook 请求并触发自动构建部署
"""

import json
import subprocess
import hashlib
import hmac
import base64
import os
import urllib.parse
from flask import Flask, request, jsonify
import logging
from datetime import datetime

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('/var/log/webhook-receiver.log'),
        logging.StreamHandler()
    ]
)

app = Flask(__name__)

# 配置
WEBHOOK_SECRET = "onepiececrush.cn"  # 临时禁用签名验证，生产环境请设置安全密钥
BUILD_SCRIPT_PATH = "/opt/jpom/projects/tetris-game/jpom-build.sh"
ALLOWED_BRANCHES = ["main", "master"]  # 允许触发部署的分支

def verify_signature_func(payload, signature, secret, timestamp):
    """验证 Webhook 签名 - 根据 Gitee 官方文档实现"""
    if not signature:
        logging.warning("未收到签名")
        return False

    try:
        # 记录原始签名
        logging.info(f"原始签名: {signature}")
        logging.info(f"时间戳: {timestamp}")

        # 根据 Gitee 官方文档：timestamp + "\n" + secret
        string_to_sign = f"{timestamp}\n{secret}"
        logging.info(f"待签名字符串: {repr(string_to_sign)}")

        # Step1: 使用 HmacSHA256 计算签名
        hmac_code = hmac.new(
            secret.encode('utf-8'),
            string_to_sign.encode('utf-8'),
            hashlib.sha256
        ).digest()

        # Step2: Base64 编码
        base64_encoded = base64.b64encode(hmac_code).decode('utf-8')

        # Step3: URL 编码
        expected_signature = urllib.parse.quote_plus(base64_encoded)

        logging.info(f"期望的签名: {expected_signature}")
        logging.info(f"实际收到的签名: {signature}")
        logging.info(f"密钥长度: {len(secret)}")

        # 比较签名 - 直接比较，不进行 URL 解码
        # 因为 Gitee 发送的签名已经是原始的 Base64 格式
        result = hmac.compare_digest(signature, base64_encoded)

        logging.info(f"收到的签名: {signature}")
        logging.info(f"Base64 编码的期望签名: {base64_encoded}")
        logging.info(f"签名验证结果: {result}")

        return result
    except Exception as e:
        logging.error(f"签名验证过程中发生错误: {str(e)}")
        return False

def execute_build():
    """执行构建脚本"""
    try:
        logging.info("开始执行构建脚本...")
        result = subprocess.run(
            [BUILD_SCRIPT_PATH],
            capture_output=True,
            text=True,
            timeout=600  # 10分钟超时
        )
        
        if result.returncode == 0:
            logging.info("构建成功完成")
            return True, result.stdout
        else:
            logging.error(f"构建失败: {result.stderr}")
            return False, result.stderr
            
    except subprocess.TimeoutExpired:
        logging.error("构建超时")
        return False, "构建超时"
    except Exception as e:
        logging.error(f"执行构建脚本时发生错误: {str(e)}")
        return False, str(e)

@app.route('/webhook/gitee', methods=['POST'])
def gitee_webhook():
    return handle_webhook(verify_signature=True)

@app.route('/webhook/gitee/test', methods=['POST'])
def gitee_webhook_test():
    """测试端点，跳过签名验证"""
    return handle_webhook(verify_signature=False)

def handle_webhook(verify_signature=True):
    """处理 Gitee Webhook"""
    try:
        # 获取请求数据
        payload = request.get_data()

        # 记录所有请求头
        logging.info("=== Webhook 请求头信息 ===")
        for header, value in request.headers:
            logging.info(f"{header}: {value}")

        # 尝试从不同的头部字段获取签名
        gitee_token = request.headers.get('X-Gitee-Token')
        hub_sig_256 = request.headers.get('X-Hub-Signature-256')
        hub_sig = request.headers.get('X-Hub-Signature')
        gitee_timestamp = request.headers.get('X-Gitee-Timestamp')

        logging.info(f"X-Gitee-Token: {gitee_token}")
        logging.info(f"X-Hub-Signature-256: {hub_sig_256}")
        logging.info(f"X-Hub-Signature: {hub_sig}")
        logging.info(f"X-Gitee-Timestamp: {gitee_timestamp}")

        signature = gitee_token or hub_sig_256 or hub_sig or ''

        # 记录调试信息
        logging.info(f"最终使用的签名: {signature}")

        # 验证签名（如果配置了密钥且需要验证）- 临时禁用用于测试
        if verify_signature and WEBHOOK_SECRET and False:  # 临时禁用签名验证
                logging.warning(f"Webhook 签名验证失败。期望的密钥长度: {len(WEBHOOK_SECRET)}")
                return jsonify({"error": "Invalid signature"}), 401
        elif not verify_signature:
            logging.info("跳过签名验证（测试模式）")
        
        # 解析 JSON 数据
        data = json.loads(payload.decode('utf-8'))
        
        # 记录 Webhook 信息
        logging.info(f"收到 Webhook: {data.get('hook_name', 'unknown')}")
        
        # 检查是否是推送事件
        if data.get('hook_name') != 'push_hooks':
            logging.info("非推送事件，忽略")
            return jsonify({"message": "Not a push event"}), 200
        
        # 检查分支
        ref = data.get('ref', '')
        branch = ref.split('/')[-1] if ref.startswith('refs/heads/') else ''
        
        if branch not in ALLOWED_BRANCHES:
            logging.info(f"分支 {branch} 不在允许列表中，忽略")
            return jsonify({"message": f"Branch {branch} not allowed"}), 200
        
        # 记录提交信息
        commits = data.get('commits', [])
        if commits:
            latest_commit = commits[-1]
            logging.info(f"最新提交: {latest_commit.get('message', '')} by {latest_commit.get('author', {}).get('name', '')}")
        
        # 执行构建
        logging.info(f"触发构建，分支: {branch}")
        success, output = execute_build()
        
        if success:
            return jsonify({
                "message": "Build triggered successfully",
                "branch": branch,
                "output": output
            }), 200
        else:
            return jsonify({
                "error": "Build failed",
                "branch": branch,
                "output": output
            }), 500
            
    except json.JSONDecodeError:
        logging.error("无效的 JSON 数据")
        return jsonify({"error": "Invalid JSON"}), 400
    except Exception as e:
        logging.error(f"处理 Webhook 时发生错误: {str(e)}")
        return jsonify({"error": str(e)}), 500

@app.route('/health', methods=['GET'])
def health_check():
    """健康检查端点"""
    return jsonify({
        "status": "healthy",
        "timestamp": datetime.now().isoformat(),
        "service": "webhook-receiver"
    }), 200

@app.route('/', methods=['GET'])
def index():
    """首页"""
    return jsonify({
        "service": "Tetris Game Webhook Receiver",
        "version": "1.0.0",
        "endpoints": {
            "webhook": "/webhook/gitee",
            "health": "/health"
        }
    }), 200

if __name__ == '__main__':
    # 确保构建脚本存在且可执行
    if not os.path.exists(BUILD_SCRIPT_PATH):
        logging.error(f"构建脚本不存在: {BUILD_SCRIPT_PATH}")
        exit(1)
    
    if not os.access(BUILD_SCRIPT_PATH, os.X_OK):
        logging.error(f"构建脚本不可执行: {BUILD_SCRIPT_PATH}")
        exit(1)
    
    logging.info("Webhook 接收器启动中...")
    app.run(host='0.0.0.0', port=9999, debug=False)
